﻿using System;
using System.IO;
using System.Windows;
using System.Windows.Resources;

using ICSharpCode.SharpZipLib;

namespace FirstFloor.Documents.IO.SharpZipLib
{
    /// <summary>
    /// Provides access to a zip file using the SharpZipLib library.
    /// </summary>
    /// <remarks>SharpZipLib provides much better performance over the built-in DefaultZipPackageReader
    /// that uses Application.GetResource. Furthermore the SharpZipLib library supports
    /// the zip format that is generated by Microsoft XPS Document Printer.</remarks>
    public class SharpZipPackageReader
        : IPackageReader
    {
        private ICSharpCode.SharpZipLib.ZipFile zip;
        private bool disposed;

        /// <summary>
        /// Initializes a new instance of the <see cref="SharpZipPackageReader"/> class.
        /// </summary>
        /// <param name="resourceUri">The resource URI.</param>
        public SharpZipPackageReader(Uri resourceUri)
        {
            if (resourceUri == null) {
                throw new ArgumentNullException("resourceUri");
            }
            var streamInfo = Application.GetResourceStream(resourceUri);
            if (streamInfo == null) {
                throw new ArgumentException(string.Format("Resource '{0}' not found", resourceUri));
            }

            Initialize(streamInfo.Stream);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SharpZipPackageReader"/> class.
        /// </summary>
        /// <param name="zipPackage">The zip package.</param>
        public SharpZipPackageReader(Stream zipPackage)
        {
            Initialize(zipPackage);
        }

        private void Initialize(Stream stream)
        {
            if (stream == null) {
                throw new ArgumentNullException("stream");
            }
            this.zip = new ICSharpCode.SharpZipLib.ZipFile(stream);
            this.zip.IsStreamOwner = true;
        }

        /// <summary>
        /// Initializes a new package part request.
        /// </summary>
        /// <param name="partUri">The part URI.</param>
        /// <returns>The part request.</returns>
        public IPackagePartRequest CreatePartRequest(Uri partUri)
        {
            return new SharpZipPackagePartRequest(this.zip, partUri);
        }

        /// <summary>
        /// Resolves the specified uri to a public accessible uri.
        /// </summary>
        /// <param name="partUri">The part URI.</param>
        /// <returns>The resolved URI.</returns>
        /// <remarks>If the package reader does not support public accessible uri's, null is returned.</remarks>
        public Uri ResolvePartUri(Uri partUri)
        {
            return null;
        }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            if (!this.disposed) {
                this.disposed = true;
                this.zip.Close();
            }
        }
    }
}
